using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Web.Services;
using System.Xml;
using Microsoft.SharePoint;

namespace SPDevExplorer.WebServices
{
    [WebService(Namespace = "http://thekid.me.uk/webservices/sharepoint"),
     WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class DevServices : WebService
    {
        /// <summary>
        /// Get the version number of the webservice.
        /// </summary>
        /// <returns>The version number.</returns>
        [WebMethod]
        public string CurrentWebServiceVersion()
        {
            return SPDevExplorer.WebServices.WebServiceVersionNumber.Current;
        }

        [WebMethod]
        public string ListFolders(string folderID)
        {
            return BuildFolderXml(folderID).DocumentElement.InnerXml;
        }

        [WebMethod]
        public string ListSiteFolders()
        {
            return BuildFolderXml(null).DocumentElement.InnerXml;
        }

        [WebMethod]
        public string CheckoutFile(string fileUrl)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                oFile.CheckOut();
                return FileDetails(oFile);
            }
        }

        [WebMethod]
        public string CreateFile(string folderID, string fileName)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                if (!folderID.StartsWith("{")) folderID = "{" + folderID + "}";
                SPFolder oFolder = oWeb.GetFolder(new Guid(folderID));

                SPFile oFile = oFolder.Files.Add(fileName, new byte[] {});

                return FileDetails(oFile);
            }
        }

        private string FileDetails(SPFile oFile)
        {
            XmlDocument oDoc = new XmlDocument();
            oDoc.LoadXml("<Response/>");
            AddFileElement(oDoc.DocumentElement, oFile);
            return oDoc.DocumentElement.InnerXml;
        }

        [WebMethod]
        public string UndoCheckoutFile(string fileUrl)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                oFile.UndoCheckOut();
                return FileDetails(oFile);
            }
        }

        [WebMethod]
        public string RefreshFileDetails(string fileUrl)
        {
            if (SpecialFile(fileUrl)) return "";
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                return FileDetails(oWeb.GetFile(fileUrl));
            }
        }

        public bool SpecialFile(string fileUrl)
        {
            if (fileUrl.Substring(1, 2) == ":\\")
                return true;

            if (fileUrl.StartsWith("CT:"))
                return true;

            return false;
        }

        [WebMethod]
        public string CheckinFile(string fileUrl)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                oFile.CheckIn("Checked in by SPDevExplorer");
                return FileDetails(oFile);
            }
        }

        [WebMethod]
        public string Publish(string fileUrl)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                oFile.Publish("Published by SPDevExplorer");
                return FileDetails(oFile);
            }
        }

        [WebMethod]
        public string Approve(string fileUrl)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                if (oFile.Item != null)
                {
                    SPModerationInformation moderationInformation = oFile.Item.ModerationInformation;
                    if (moderationInformation != null && moderationInformation.Status != SPModerationStatusType.Approved)
                    {
                        oFile.Approve("Aproved by SPDevExplorer");
                    }
                }
                return FileDetails(oFile);
            }
        }

        [WebMethod]
        public string PublishAndApprove(string fileUrl)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                oFile.Publish("Published by SPDevExplorer");

                // SvdO: If approval is enabled on a document library, publish is not enough, will create minor version
                if (oFile.Item != null)
                {
                    SPModerationInformation moderationInformation = oFile.Item.ModerationInformation;
                    if (moderationInformation != null && moderationInformation.Status != SPModerationStatusType.Approved)
                    {
                        oFile.Approve("Aproved by SPDevExplorer");
                    }
                }
                return FileDetails(oFile);
            }
        }

        [WebMethod]
        public string RenameFile(string fileUrl, string newName)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                string sUrl = oFile.Url.Substring(0, oFile.Url.LastIndexOf("/") + 1);
                oFile.MoveTo(sUrl + newName, false);
                oFile.Update();
                return FileDetails(oFile);
            }
        }

        [WebMethod]
        public string CopyFile(string fileUrl, string newName)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                string sUrl = oFile.Url.Substring(0, oFile.Url.LastIndexOf("/") + 1);
                oFile.CopyTo(sUrl + newName, false);
                oFile.Update();
                return FileDetails(oFile);
            }
        }

        [WebMethod]
        public string GetFile(string fileUrl)
        {
            if (fileUrl.Substring(1, 2) == ":\\")
                return LoadLogFile(fileUrl);

            if (fileUrl.StartsWith("CT:"))
                return LoadContentType(fileUrl);

            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                return oWeb.GetFileAsString(fileUrl);
            }
        }

        [WebMethod]
        public byte[] GetFileBytes(string fileUrl)
        {
            if (SpecialFile(fileUrl)) return null;

            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                return oFile.OpenBinary();
            }
        }

        private string LoadContentType(string fileUrl)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPContentTypeId id = new SPContentTypeId(fileUrl.Substring(3));
                SPContentType ct = oWeb.ContentTypes[id];
                return ct.SchemaXml;
            }
        }

        [WebMethod]
        public string NewFolder(string folderID, string newFolderName)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                if (!folderID.StartsWith("{")) folderID = "{" + folderID + "}";
                SPFolder oFolder = oWeb.GetFolder(new Guid(folderID));

                SPFolder newFolder = oFolder.SubFolders.Add(newFolderName);
                return ListFolders(newFolder.UniqueId.ToString());
            }
        }

        [WebMethod]
        public string RenameFolder(string folderID, string newFolderName)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                if (!folderID.StartsWith("{")) folderID = "{" + folderID + "}";
                SPFolder oFolder = oWeb.GetFolder(new Guid(folderID));

                string sUrl = oFolder.Url.Substring(0, oFolder.Url.LastIndexOf("/") + 1);
                oFolder.MoveTo(sUrl + newFolderName);
                oFolder.Update();

                return oFolder.Url;
            }
        }

        [WebMethod]
        public void DeleteFolder(string folderID)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                if (!folderID.StartsWith("{")) folderID = "{" + folderID + "}";
                SPFolder oFolder = oWeb.GetFolder(new Guid(folderID));
                oFolder.Delete();
            }
        }

        private string LoadLogFile(string fileUrl)
        {
            string sReturn = "";
            SPSecurity.RunWithElevatedPrivileges(delegate
                                                     {
                                                         //sReturn = System.IO.File.ReadAllText(fileUrl);
                                                         using (
                                                             FileStream fs = new FileStream(fileUrl, FileMode.Open,
                                                                                            FileAccess.Read,
                                                                                            FileShare.ReadWrite))
                                                         {
                                                             StreamReader rdr = new StreamReader(fs);
                                                             sReturn = rdr.ReadToEnd();
                                                             rdr.Close();
                                                             fs.Close();
                                                         }
                                                     });
            return sReturn;
        }

        [WebMethod]
        public void DeleteFile(string fileUrl)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                oFile.Delete();
            }
        }

        [WebMethod]
        public void SaveFile(string fileUrl, string contents)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                byte[] arBytes = Encoding.UTF8.GetBytes(contents);
                oFile.SaveBinary(arBytes);
            }
        }

        [WebMethod]
        public void SaveFileBytes(string fileUrl, byte[] fileBytes)
        {
            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFile oFile = oWeb.GetFile(fileUrl);
                oFile.SaveBinary(fileBytes);
            }
        }

        private XmlDocument BuildFolderXml(string folderID)
        {
            XmlDocument oDoc = new XmlDocument();
            oDoc.LoadXml("<Folders/>");

            // if (BuildSpecialFolder(folderID, oDoc)) return oDoc;

            using (SPWeb oWeb = SPContext.Current.Site.OpenWeb())
            {
                SPFolder oRootFolder = oWeb.RootFolder;

                if (!string.IsNullOrEmpty(folderID))
                {
                    if (!folderID.StartsWith("{")) folderID = "{" + folderID + "}";
                    oRootFolder = oWeb.GetFolder(new Guid(folderID));
                }

                XmlElement oFolder = AddFolder(oDoc.DocumentElement, oRootFolder, true, 1);

                if (string.IsNullOrEmpty(folderID))
                {
                    AddSubWebs(oWeb, oFolder);
                    AddRootWebElements(oDoc, oWeb, oFolder);
                }
            }

            return oDoc;
        }

        private void AddSubWebs(SPWeb oWeb, XmlElement oFolder)
        {
            try
            {
                SPWebCollection oWebs = oWeb.Webs;
                foreach (SPWeb oSubWeb in oWebs)
                {
                    XmlElement oWebXml = oFolder.OwnerDocument.CreateElement("Web");
                    oFolder.AppendChild(oWebXml);
                    oWebXml.SetAttribute("Name", oWeb.Name);
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
            }
        }

        private void AddRootWebElements(XmlDocument oDoc, SPWeb oWeb, XmlElement oFolder)
        {
            AddWebProperties(oWeb, oFolder);
// SvdO: Site & System with log files and content types seems of no use
#if false
            XmlElement oSiteInfo = oDoc.CreateElement("Folder");
            oSiteInfo.SetAttribute("System", bool.TrueString);
            oSiteInfo.SetAttribute("Name", "Site & System");
            oSiteInfo.SetAttribute("ItemCount", "2");
            oSiteInfo.SetAttribute("ReadOnly", bool.TrueString);

            oFolder.AppendChild(oSiteInfo);

            BuildLogsElement(oSiteInfo);
            BuildContentTypesElement(oSiteInfo, oWeb);
#endif
        }

        private void AddWebProperties(SPWeb oWeb, XmlElement xmlElement)
        {
            try
            {
                XmlElement oWebProps = xmlElement.OwnerDocument.CreateElement("WebProperties");
                xmlElement.AppendChild(oWebProps);

                oWebProps.SetAttribute("AllowAnonymousAccess", oWeb.AllowAnonymousAccess.ToString());
                oWebProps.SetAttribute("AllowAutomaticASPXPageIndexing", oWeb.AllowAutomaticASPXPageIndexing.ToString());
                oWebProps.SetAttribute("AllowRssFeeds", oWeb.AllowRssFeeds.ToString());
                oWebProps.SetAttribute("AlternateCssUrl", oWeb.AlternateCssUrl);
                oWebProps.SetAttribute("AlternateHeader", oWeb.AlternateHeader);
                oWebProps.SetAttribute("ASPXPageIndexed", oWeb.ASPXPageIndexed.ToString());
                oWebProps.SetAttribute("ASPXPageIndexMode", oWeb.ASPXPageIndexMode.ToString());
                oWebProps.SetAttribute("AuthenticationMode", oWeb.AuthenticationMode.ToString());
                oWebProps.SetAttribute("Author", oWeb.Author.Name);
                oWebProps.SetAttribute("CacheAllSchema", oWeb.CacheAllSchema.ToString());
                oWebProps.SetAttribute("Created", oWeb.Created.ToShortDateString());
                oWebProps.SetAttribute("CustomMasterUrl", oWeb.CustomMasterUrl);
                oWebProps.SetAttribute("Description", oWeb.Description);
                oWebProps.SetAttribute("EventHandlersEnabled", oWeb.EventHandlersEnabled.ToString());
                oWebProps.SetAttribute("IsRootWeb", oWeb.IsRootWeb.ToString());
                oWebProps.SetAttribute("LastItemModifiedDate", oWeb.LastItemModifiedDate.ToShortDateString());
                oWebProps.SetAttribute("Locale", oWeb.Locale.DisplayName);
                oWebProps.SetAttribute("MasterUrl", oWeb.MasterUrl);
                oWebProps.SetAttribute("NoCrawl", oWeb.NoCrawl.ToString());
                oWebProps.SetAttribute("PortalName", oWeb.PortalName);
                oWebProps.SetAttribute("PortalSubscriptionUrl", oWeb.PortalSubscriptionUrl);
                oWebProps.SetAttribute("PortalUrl", oWeb.PortalUrl);
                oWebProps.SetAttribute("PresenceEnabled", oWeb.PresenceEnabled.ToString());
                oWebProps.SetAttribute("PublicFolderRootUrl", oWeb.PublicFolderRootUrl);
                oWebProps.SetAttribute("WebTemplate", oWeb.WebTemplate);
                oWebProps.SetAttribute("WebTemplateId", oWeb.WebTemplateId.ToString());
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
            }
        }

//SvdO: see no need for this, use web UI
#if false
        private void BuildContentTypesElement(XmlElement oParent, SPWeb oWeb)
        {
            XmlElement oCTs = oParent.OwnerDocument.CreateElement("Folder");
            oParent.AppendChild(oCTs);

            oCTs.SetAttribute("System", bool.TrueString);
            oCTs.SetAttribute("Name", "Content Types");
            oCTs.SetAttribute("ID", "CoontentTypes");
            oCTs.SetAttribute("ItemCount", oWeb.ContentTypes.Count.ToString());
            oCTs.SetAttribute("ReadOnly", bool.TrueString);

            foreach (SPContentType ct in oWeb.ContentTypes)
            {
                XmlElement oCTXml = oCTs.OwnerDocument.CreateElement("File");
                oCTs.AppendChild(oCTXml);
                oCTXml.SetAttribute("System", bool.TrueString);
                oCTXml.SetAttribute("Name", ct.Name);
                oCTXml.SetAttribute("ID", "ContentType");
                oCTXml.SetAttribute("Url", "CT:" + ct.Id.ToString());
                oCTXml.SetAttribute("Group", ct.Group);
                oCTXml.SetAttribute("DocumentTemplate", ct.DocumentTemplate);
            }
        }
#endif

//SvdO: see no use for this, use other tools
#if false
        private XmlElement BuildLogsElement(XmlElement oParent)
        {
            XmlElement oLogs = oParent.OwnerDocument.CreateElement("Folder");
            oParent.AppendChild(oLogs);
            oLogs.SetAttribute("System", bool.TrueString);
            oLogs.SetAttribute("Name", "Logs");
            oLogs.SetAttribute("ID", "Logs");
            oLogs.SetAttribute("ItemCount", "10");
            oLogs.SetAttribute("ReadOnly", bool.TrueString);

            return oLogs;
        }

        private bool BuildSpecialFolder(string folderID, XmlDocument oDoc)
        {
            if (folderID == "Logs")
            {
                try
                {
                    BuildLogs(BuildLogsElement(oDoc.DocumentElement));
                }
                catch
                {
                    SPSecurity.RunWithElevatedPrivileges(delegate { BuildLogs(BuildLogsElement(oDoc.DocumentElement)); });
                }
                return true;
            }

            return false;
        }

        private void BuildLogs(XmlElement oParent)
        {
            try
            {
                Microsoft.Win32.RegistryKey k = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Shared Tools\\Web Server Extensions\\12.0\\WSS");
                string sLocation = (string)k.GetValue("LogDir");
                k.Close();
                string[] arLogs = System.IO.Directory.GetFiles(sLocation);
                foreach (string sFile in arLogs)
                {
                    System.IO.FileInfo fi = new System.IO.FileInfo(sFile);
                    if (!fi.Name.StartsWith("PSCD"))
                    {
                        XmlElement oFile = oParent.OwnerDocument.CreateElement("File");
                        oFile.SetAttribute("Name", fi.Name);
                        oFile.SetAttribute("Url", fi.FullName);
                        oParent.AppendChild(oFile);
                    }
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
            }
        }
#endif

        private XmlElement AddFolder(XmlElement oWebFolder, SPFolder oFolder, bool isRoot, int subFolderCount)
        {
            XmlElement oFolderElement =
                (XmlElement) oWebFolder.SelectSingleNode("Folder[@Name=\"" + oFolder.Name + "\"]");

            if (oFolderElement == null)
            {
                oFolderElement = oWebFolder.OwnerDocument.CreateElement("Folder");
                oWebFolder.AppendChild(oFolderElement);

                if (subFolderCount < 2)
                {
                    foreach (SPFile oFile in oFolder.Files)
                        AddFileElement(oFolderElement, oFile);
                }
            }

            oFolderElement.SetAttribute("System", bool.FalseString);
            oFolderElement.SetAttribute("Name", oFolder.Name);
            oFolderElement.SetAttribute("Url", oFolder.Url);
            oFolderElement.SetAttribute("ItemCount", oFolder.Files.Count.ToString());
            oFolderElement.SetAttribute("FolderCount", oFolder.SubFolders.Count.ToString());
            oFolderElement.SetAttribute("ID", oFolder.UniqueId.ToString());
            oFolderElement.SetAttribute("IsRoot", isRoot.ToString());

            oFolderElement.SetAttribute("ParentListId", oFolder.ParentListId.ToString());
            oFolderElement.SetAttribute("WelcomePage", oFolder.WelcomePage);

            oFolderElement.SetAttribute("IsDocumentLibrary", bool.FalseString);
            oFolderElement.SetAttribute("EnableMinorVersions", bool.FalseString);
            oFolderElement.SetAttribute("EnableModeration", bool.FalseString);
            oFolderElement.SetAttribute("EnableVersioning", bool.FalseString);
            oFolderElement.SetAttribute("ForceCheckout", bool.FalseString);

            AddPropertiesElement(oFolder.Properties, oFolderElement);

            if (oFolder.ContainingDocumentLibrary != Guid.Empty)
            {
                SPList oList = oFolder.ParentWeb.Lists[oFolder.ContainingDocumentLibrary];

                if (string.Compare(oList.RootFolder.Url, oFolder.Url, true) == 0)
                {
                    oFolderElement.SetAttribute("Description", oList.Description);
                    oFolderElement.SetAttribute("IsDocumentLibrary", bool.TrueString);
                }
                oFolderElement.SetAttribute("EnableMinorVersions", oList.EnableMinorVersions.ToString());
                oFolderElement.SetAttribute("EnableModeration", oList.EnableModeration.ToString());
                oFolderElement.SetAttribute("EnableVersioning", oList.EnableVersioning.ToString());
                oFolderElement.SetAttribute("ForceCheckout", oList.ForceCheckout.ToString());
            }

            if (subFolderCount < 2)
            {
                foreach (SPFolder oSubFolder in oFolder.SubFolders)
                    AddFolder(oFolderElement, oSubFolder, false, subFolderCount + 1);
            }

            return oFolderElement;
        }

        private static void AddPropertiesElement(Hashtable oProps, XmlElement oParent)
        {
            try
            {
                XmlElement oProperties = oParent.OwnerDocument.CreateElement("Properties");
                oParent.AppendChild(oProperties);
                foreach (string sKey in oProps.Keys)
                {
                    XmlElement oProperty = oProperties.OwnerDocument.CreateElement("Property");
                    oProperty.SetAttribute("Name", sKey);
                    oProperty.InnerText = oProps[sKey].ToString();
                    oProperties.AppendChild(oProperty);
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
            }
        }

        private void AddFileElement(XmlElement oFolderElement, SPFile oFile)
        {
            XmlElement oFileXml = oFolderElement.OwnerDocument.CreateElement("File");
            oFolderElement.AppendChild(oFileXml);

            oFileXml.SetAttribute("Name", oFile.Name);
            oFileXml.SetAttribute("Title", oFile.Title);
            oFileXml.SetAttribute("Url", oFile.Url);
            oFileXml.SetAttribute("ServerRelativeUrl", oFile.ServerRelativeUrl);
            oFileXml.SetAttribute("ID", oFile.UniqueId.ToString());
            oFileXml.SetAttribute("CheckOutStatus", oFile.CheckOutStatus.ToString());
            // SvdO: 
            oFileXml.SetAttribute("Level", oFile.Level.ToString());
            oFileXml.SetAttribute("MajorVersion", oFile.MajorVersion.ToString());
            oFileXml.SetAttribute("MinorVersion", oFile.MinorVersion.ToString());

            try
            {
                if (oFile.Item != null)
                {
                    SPModerationInformation moderationInformation = oFile.Item.ModerationInformation;
                    if (moderationInformation != null)
                    {
                        // Possible values: 
                        // Approved - The item is displayed in public views of the list or document library. 
                        // Denied - The item is not displayed in public views of the list or document library. 
                        // Pending - The decision about displaying the item in public views of the list or document library is pending.  

                        oFileXml.SetAttribute("ModerationStatus", Enum.GetName(typeof(SPModerationStatusType), moderationInformation.Status));
                    }
                }
            }
            catch
            {
            }

            oFileXml.SetAttribute("Exists", oFile.Exists.ToString());

            AddPropertiesElement(oFile.Properties, oFileXml);

            try
            {
                if (oFile.Item != null)
                    oFileXml.SetAttribute("HasPublishedVersion", oFile.Item.HasPublishedVersion.ToString());
            }
            catch
            {
            }

            if (oFile.CheckedOutBy == null)
            {
                oFileXml.SetAttribute("CheckedOutBy", "");
                oFileXml.SetAttribute("HasCheckedOut", bool.FalseString);
            }
            else
            {
                oFileXml.SetAttribute("CheckedOutBy", oFile.CheckedOutBy.Name);
                oFileXml.SetAttribute("HasCheckedOut",
                                      ((bool)
                                       (oFile.CheckedOutBy.LoginName.ToLower() ==
                                        SPContext.Current.Web.CurrentUser.LoginName.ToLower())).ToString());
                oFileXml.SetAttribute("CheckedOutByLogin", oFile.CheckedOutBy.LoginName);
                oFileXml.SetAttribute("WebLogin", SPContext.Current.Web.CurrentUser.LoginName);
            }

            // SvdO: Need last modified date to prevent overwrite, serialize as ISO-8601, parse with DateTime.Parse()
            oFileXml.SetAttribute("TimeLastModified", oFile.TimeLastModified.ToString("s"));
        }
    }
}